package com.spring.demo.spring.core.context;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.spring.demo.spring.core.annoation.Autowartied;
import com.spring.demo.spring.core.annoation.ComponentFree;
import com.spring.demo.spring.core.annoation.ComponentScanFree;
import com.spring.demo.spring.core.annoation.Scope;
import com.spring.demo.spring.core.defnation.BeanDefinition;
import com.spring.demo.spring.core.util.ScopeEnum;
import lombok.SneakyThrows;
import com.spring.demo.spring.core.context.BeanPostProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author RenPu
 * @Date 2024/2/15 19:51
 * @Version 1.0
 * @Description: 自定义实现模拟spring的上下文对象
 **/

@Slf4j
public class  GenrnicApplicationContext <T>{

    private Class<T> appClass;

    //beanDefinition 对象的容器
    private Map<String,BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<>(256);

    //单例池
    private Map<String,Object> singletonMap=new ConcurrentHashMap<>(256);

    private List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>(256);

    @SneakyThrows
    public GenrnicApplicationContext(Class<T> appClass) {
        this.appClass = appClass;

        //扫描，加载，校验注解，封装BeanDefinition对象存储到beanDefinitionMap中
        doScan(appClass);

        //过滤beanDefinitionMap的单例对象，进行对象的创建并且存放到singletonMap中

        for (Map.Entry<String, BeanDefinition> entry :  beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();
            if(beanDefinition.getScope().equals(ScopeEnum.singleton.name())){
                //开始创建bean
                Object obj=doCreateBean(entry.getKey(),beanDefinition);
                singletonMap.put(entry.getKey(),obj);

            }
        }



    }


    /**
     * 扫描，加载，校验注解，封装BeanDefinition对象
     * @param appClass
     */
    private void doScan(Class<T> appClass) throws Exception {
        //1：根据appClass类进行校验是否有ComponentScan注解
        if(appClass.isAnnotationPresent(ComponentScanFree.class)){

            ComponentScanFree componentScanFree = appClass.getAnnotation(ComponentScanFree.class);
            //2 将包路径替换为文件路径 ,com.spring.demo.spring.core.applicationprocess变为com/spring/demo/spring/core/applicationprocess
            String path = componentScanFree.value().replace(".","/");

            //3 获取类加载器，根据文件路径加载对象
            ClassLoader classLoader = GenrnicApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            File file = new File(resource.getFile());
            File[] listFiles = file.listFiles();

            if(file.isDirectory()){
                for (File f : listFiles) {
                    String absolutePath = f.getAbsolutePath();
                    //4 利用类加载器机制，将class文件加载为class对象
                    Class<?> aClass = null;
                    try {
                        String classPath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                                .replace("\\", ".");
                        log.info("类加载器需要加载资源得路径"+classPath);
                        aClass = classLoader.loadClass(classPath);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }

                    if(aClass.isAnnotationPresent(ComponentFree.class)){

                        //处理spring设计的扩展点 BeanPostProcessor的设计与实现
                        if(BeanPostProcessor.class.isAssignableFrom(aClass)){
                            BeanPostProcessor instance=(BeanPostProcessor) aClass.getConstructor().newInstance();
                            beanPostProcessorList.add(instance);
                        }

                        ComponentFree annotation = aClass.getAnnotation(ComponentFree.class);
                        String beanName = annotation.value();
                        if(StrUtil.isBlank(beanName)){

                            //如果ComponentFree注解，没有指定bean的名字，则直接根据类的名字进行设定
                            beanName= Introspector.decapitalize(aClass.getSimpleName());
                        }

                        BeanDefinition beandef = new BeanDefinition();
                        beandef.setType(aClass);
                        if(aClass.isAnnotationPresent(Scope.class)){
                            Scope scopeAnno = aClass.getAnnotation(Scope.class);
                            beandef.setScope(scopeAnno.value());
                        }else {
                            //单例
                            beandef.setScope(ScopeEnum.singleton.name());
                        }

                        //放入beanDefinitionMap中，便于后续创建bean进行获取
                        beanDefinitionMap.put(beanName,beandef);
                    }

                }

            }
        }
    }


    /**
     * 创建Bean的核心方法
     * 创建Bean，存放到单例池中
     * @return
     */
    public Object doCreateBean(String beanNamem,BeanDefinition definition){
        Class type = definition.getType();
        Object instance = null;
        try {

            //默认使用无参构造方法，进行创建Bean对象
            instance = type.getConstructor().newInstance();

            // 获取类所有的成员变量 校验是否有Autowrited注解
            Field[] declaredFields = instance.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if(declaredField.isAnnotationPresent(Autowartied.class)){
                    declaredField.setAccessible(true);
                    declaredField.set(instance, getBean( declaredField.getName()));
                }
            }

            //检验是否有实现的接口(InitializingBean)
            if(instance instanceof InitializingBean){
                 ((InitializingBean) instance).afterPropertiesSet();
            }

            //检验是否有实现的接口(BeanNameAware)
            if(instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanNamem);
            }


            //检验是否有实现的接口(BeanPostProcessor)
            for (BeanPostProcessor beanPostProcessor :beanPostProcessorList) {
                instance= beanPostProcessor.postProcessBeforeInitialization(instance,beanNamem);
            }
            for (BeanPostProcessor beanPostProcessor :beanPostProcessorList) {
                instance =beanPostProcessor.postProcessAfterInitialization(instance,beanNamem);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }




    /**
     * 获取Bean的方法
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {

        //1:先从beanDefinitionMap中校验是否包含
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }

        //2:根据beanName获取出beanDefinition对象，校验scope的类型
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //3：校验scope的是单例还是属于原型，选择不同的创建对象的方式
        if(beanDefinition.getScope().equals(ScopeEnum.singleton.name())){
            //单例每次从单例池中获取
         Object  singletonBean= singletonMap.get(beanName);
         if(ObjectUtil.isEmpty(singletonBean)){
               singletonBean=doCreateBean(beanName,beanDefinition);
               singletonMap.put(beanName, beanDefinition);
         }
           return singletonBean;
        }else {
            //原型每次都进行主动创建
          Object protroTypeBean = doCreateBean(beanName,beanDefinition);
            return protroTypeBean;
        }
    }
}
